package com.gking.aiService.realm;


import com.alibaba.fastjson.JSON;
import com.gking.aiService.common.ResultResponse;
import com.gking.aiService.serviceUtils.RemoteInteraction.RemoteInteractionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.gking.aiService.common.RedisConstants.*;


@Slf4j
@Component
public class MyRealm extends AuthorizingRealm {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RemoteInteractionService remoteInteractionService;


    //自定义授权方法：获取当前登录用户权限信息，返回给 Shiro 用来进行授权对比
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1、获取用户身份信息
        String principal = principalCollection.getPrimaryPrincipal().toString();
        log.warn("MyRealm 自定义授权方法，查询到的用户 principal : {}", principal);

        List<String> roleList;
        List<String> permissionsList;
        String rolesString = stringRedisTemplate.opsForValue().get(Login_User_Roles + principal);
        String permissionsString = stringRedisTemplate.opsForValue().get(Login_User_Permissions + principal);

        if (rolesString == null || permissionsString == null) {
            //2、调用业务层获取用户的角色信息(数据库)
            ResultResponse userRolesDetail = remoteInteractionService.getUserRolesDetail();
            Map<String, List<String>> dataMap = (Map<String, List<String>>) userRolesDetail.getData();
            roleList = dataMap.get("roleNameList");
            stringRedisTemplate.opsForValue().set(Login_User_Roles + principal,
                    JSON.toJSONString(roleList), Login_User_Info_TTL, TimeUnit.HOURS);

            //2.1 调用业务层获取用户的权限信息（数据库）
            permissionsList = dataMap.get("permissionList");
            stringRedisTemplate.opsForValue().set(Login_User_Permissions + principal,
                    JSON.toJSONString(permissionsList), Login_User_Info_TTL, TimeUnit.HOURS);
        } else {
            // 如何redis中有角色权限缓存，则使用redis中的角色权限
            roleList = JSON.parseArray(rolesString, String.class);
            permissionsList = JSON.parseArray(permissionsString, String.class);
        }

//        log.warn("当前用户角色信息 = " + roleList);
//        log.warn("当前用户权限信息 = " + permissionsList);

        //3、 创建对象，存储当前登录的用户的权限和角色
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roleList);
        info.addStringPermissions(permissionsList);

        //4、 返回信息
        return info;
    }


    //自定义登录认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1、获取用户身份信息
        String principal = authenticationToken.getPrincipal().toString();
        log.warn("shiro 获取用户身份信息 userId : " + principal);

        Md5Hash md5Hash = new Md5Hash("constantPassword", "salt", 3);
        AuthenticationInfo info = new SimpleAuthenticationInfo(
                authenticationToken.getPrincipal().toString(),//用户标识
                md5Hash.toHex(),//经过加密处理后的用户凭据（密码）
                ByteSource.Util.bytes("salt"),//加密时的盐 ByteSource.Util.bytes("salt")
                authenticationToken.getPrincipal().toString()//realm name
        );

        return info;
    }


    //清除用户缓存
    public void clearCached() {
        PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
        log.warn("清除缓存 principals： {}", principals);
        super.clearCache(principals);
    }

}
